let app = getApp();

export class newObject {

  cancelFunction;

  backSuccessFunction; backErrorFunction; completeFunction;

  doneSuccessFunctions = []; doneFailFunctions = []; doneCompleteFunctions = [];

  next(datas) {
    if (this.backSuccessFunction) {
      const returnData = this.backSuccessFunction(datas);
      if (this.completeFunction) {
        this.completeFunction(returnData);
      }
    }

    return this.subject;
  }

  error(datas) {
    if (this.backErrorFunction) {
      const returnData = this.backErrorFunction(datas);
      if (this.completeFunction) {
        this.completeFunction(returnData);
      }
    }

    return this.subject;
  }

  cancel(cancel) {
    this.cancelFunction = cancel;
  }



  success(datas) {
    const excute = (returnData) => {
      const doneSuccessFunction = this.doneSuccessFunctions.splice(0, 1)[0];
      if (doneSuccessFunction) {
        const data = doneSuccessFunction(returnData);
        if (this.doneSuccessFunctions&&this.doneSuccessFunctions.length) {
          excute(data);
        } else {
          this.done(data);
        }
      }
    }

    excute(datas);

  }

  fail(datas) {
    const excute = (returnData) => {
      const doneFailFunction = this.doneFailFunctions.splice(0, 1)[0];
      if (doneFailFunction) {
        const data = doneFailFunction(returnData);
        if (this.doneFailFunctions&&this.doneFailFunctions.length) {
          excute(data);
        } else {
          this.done(data);
        }
      } else {
        //链式结构 then
        const doneSuccessFunction = this.doneSuccessFunctions.splice(0, 1)[0];
        if (doneSuccessFunction) {
          const data = doneSuccessFunction(returnData);
          if (this.doneSuccessFunctions&&this.doneSuccessFunctions.length) {
            excute(data);
          } else {
            this.done(data);
          }
        }
      }
    }

    excute(datas);

  }

  done(returnData) {
    if (this.doneCompleteFunctions){
      const doneCompleteFunction = this.doneCompleteFunctions.splice(0, 1)[0];
      if (doneCompleteFunction) {
        doneCompleteFunction(returnData);
      }
    }
    this.unsubscribe();
  }

  subscribe(success, fail, complete) {
    this.backSuccessFunction = success;
    this.backErrorFunction = fail;
    this.completeFunction = complete;
    return this.observable;
  }

  unsubscribe() {
    this.backErrorFunction = null;
    this.backSuccessFunction = null;
    this.cancelFunction = null;
    this.completeFunction = null;
    this.doneCompleteFunctions = null;
    this.doneFailFunctions = null;
    this.doneSuccessFunctions = null;

    delete app.objects[this.name];
  }

  then(success, fail, complete) {
    if (success) {
      this.doneSuccessFunctions.push(success);
    }
    if (fail) {
      this.doneFailFunctions.push(fail);
    }
    if (complete) {
      this.doneCompleteFunctions.push(complete);
    }
    return this.outside;
  }

  name;

  outside = {
    then: (...something) => {
      return this.then(...something);
    },
    unsubscribe: (something) => {
      return this.unsubscribe(something);
    }
  };

  observable = {
    subscribe: (something) => {
      return this.subscribe(something);
    },
    unsubscribe: (something) => {
      return this.unsubscribe(something);
    },
    then: (...something) => {
      return this.then(...something);
    }
  };

  subject = {
    next: (something) => {
      return this.next(something);
    },
    error: (something) => {
      return this.error(something);
    },
    cancel: (something) => {
      return this.cancel(something);
    },
    success: (something) => {
      return this.success(something);
    },
    fail: (something) => {
      return this.fail(something);
    }
  }

  constructor(_name) {
    this.name = _name;

    return {
      observable: this.observable,
      subject: this.subject
    };
  }

}



const subject = (name) => {
  let RXObject = app.objects[name];

  if (!RXObject) {
    RXObject = new newObject(name);
    app.objects[name] = RXObject;
  }
  return RXObject.subject;
}

const observable = (name) => {
  let RXObject = app.objects[name];

  if (!RXObject) {
    RXObject = new newObject(name);
    app.objects[name] = RXObject;
  }
  return RXObject.observable;
}

/**
 * 全局调用初始化
 */
const init = () => {
  app.objects = {};
}

const bind = (that) => {
  app = that;
  init();
}

module.exports = {
  subject,
  observable,
  init,
  bind
}
